文章内容:用 webpack 打包两个简单的模块,分析打包后的代码,也就是运行时代码。
# 代码准备
index.js
const sum = require("./sum");
console.log(sum(6, 9));
1
2
3
2
3
sum.js
module.exports = (a, b) => {
return a + b;
};
1
2
3
2
3
webpack.config.js
const path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "build"),
},
mode: "none",
};
// npx webpack --entry ./index.js --output-path build --mode=none
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
在控制台执行
npx webpack
1
在目录下输出 build/main.js
/******/ (() => {
// webpackBootstrap
/******/ var __webpack_modules__ = [
,
/* 0 */ /* 1 */
/***/ (module) => {
module.exports = (a, b) => {
return a + b;
};
/***/
},
/******/
];
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/
}
/******/ // Create a new module (and put it into the cache)
/******/ var module = (__webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {},
/******/
});
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](
module,
module.exports,
__webpack_require__
);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/
}
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
const sum = __webpack_require__(1);
console.log(sum(6, 9));
})();
/******/
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
接下来对 main.js 的代码进行分析
# 运行时代码分析
# 整体分析
main.js 整个是一个立即执行函数,首先先看一下整体
立即执行函数内包裹了五个部分的内容:
- 1、2、4 是变量的声明与赋值,
- 3 是函数的声明,
- 5 又是一个立即执行函数,
这时还不知道这些变量和函数的作用是什么,可以带着疑问去调试代码;
接下来就进行断点调试
- 将断点打在 5 这个立即执行函数内部第一行代码上
- 然后打开
JavaScript Debug Terminal
,执行node main.js
- 进入我们所打的断点位置
- 然后单步调试,看代码的执行情况
通过调试运行时代码分析得出
- 1 ->
__webpack_modules__
:是一个数组,存放所有加载到的模块。在此示例中,__webpack_modules__[0]
是空的,__webpack_modules__[1]
是 sum.js 模块; - 2 ->
__webpack_module_cache__
:是一个对象,对模块执行结果进行缓存,这样能够保证每个模块只被执行一次; - 3 ->
__webpack_require__
:是一个函数,作用是加载模块,如果模块第一次被加载,则通过__webpack_modules__[moduleId]
匹配上对应的模块,并进行缓存;如果是已加载的模块,则直接从__webpack_module_cache__[moduleId]
取; - 4 ->
__webpack_exports__
:是一个对象,存放导出的内容; - 5 -> IIFE:加载入口模块
# __webpack_require__
具体做了什么?
webpack 的模块加载器是如何实现的,见注释
/******/ (() => {
// webpackBootstrap
/******/ var __webpack_modules__ = [
,
/* 0 */ /* 1 */
/***/ (module) => {
module.exports = (a, b) => {
return a + b;
};
/***/
},
/******/
];
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // (1)检查模块是否存在于缓存中
/******/ var cachedModule = __webpack_module_cache__[moduleId];
// (2)如果缓存存在,则直接返回缓存中 moduleId 所对应的 exports 对象
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/
}
/******/ // (3)如果缓存不存在,则创建一个 module 对象,用于初始化 module 信息,同时创建对应的缓存
/******/ var module = (__webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {},
/******/
});
/******/
/******/ // (4)通过 moduleId 匹配到 __webpack_modules__ 存放的对应的模块,并传入 module, module.exports, __webpack_require__ 参数,执行模块
/******/ __webpack_modules__[moduleId](
module,
module.exports,
__webpack_require__
);
/******/
/******/ // (5)返回 module.exports
/******/ return module.exports;
/******/
}
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
const sum = __webpack_require__(1);
console.log(sum(6, 9));
})();
/******/
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 如何理解 5 -> IIFE:加载入口函数
将 main.js 改造一下
/******/ (() => {
// webpackBootstrap
/******/ var __webpack_modules__ = [
/* 0 */
() => {
const sum = __webpack_require__(1);
console.log(sum(6, 9));
},
/* 1 */
/***/ (module) => {
module.exports = (a, b) => {
return a + b;
};
/***/
},
/******/
];
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/
}
/******/ // Create a new module (and put it into the cache)
/******/ var module = (__webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {},
/******/
});
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](
module,
module.exports,
__webpack_require__
);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/
}
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
__webpack_require__(0);
/******/
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
可见 webpack
运行时代码最后是 __webpack_require__(0)
# 小结
通过对 webpack 运行时代码进行调试以及分析,如果不考虑缓存的情况,可用一句话说明其逻辑:加载入口模块,入口模块所依赖的其他模块,通过 __webpack_require__
模块加载函数进行递归加载存放在 __webpack_modules__
的对应模块。